﻿using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Windows;

namespace weBoardSvr
{
    public partial class weBoardServer
    {
        #region Properties
        /// <summary>
        /// Gets Internet state
        /// </summary>
        public bool IsInet
        {
            get { return _inetAlive; }
        }

        /// <summary>
        /// Gets server state
        /// </summary>
        public bool IsWorking { get { return _working; } }

        /// <summary>
        /// Gets external IP address
        /// </summary>
        public String ExtAddress { get { return _extAddr; } }

        /// <summary>
        /// Gets and sets connection port
        /// </summary>
        public Int32 Port {
            set
            {
                if (value > 1000 && value < 65536) 
                    _port = value;
                else _port = DefPort;
            }
        }
        #endregion Properties

        #region Public functions
        /// <summary>
        /// Resolves external host ip
        /// </summary>
        /// <returns>External IP</returns>
        public void ResolveExtIp(EventHandler callback)
        {
            _extHandler = callback;
            _checkExtIpThread = new Thread(ExtIpRoutine) { IsBackground = true, Name = "ExtIpRoutine_Thread" };
            _checkExtIpThread.Start();
        }

        /// <summary>
        /// Checks connection to external internet resource
        /// </summary>
        public void CheckInternet(PingCompletedEventHandler onPing)
        {
            try
            {
                var pingy = new Ping();
                pingy.PingCompleted += PingDoneCallback;
                if (onPing != null)
                    pingy.PingCompleted += onPing;
                pingy.SendAsync("ya.ru", 3000, new byte[32], new PingOptions(64, true));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "CheckInternet::Error occured");
                _inetAlive = false;
                if (onPing != null)
                    onPing(this, null);
            }
        }
        #endregion Public functions

        #region Private helpers
        /// <summary>
        /// Does actual work to get external IP
        /// </summary>
        private void ExtIpRoutine()
        {
            try
            {
                var req = (HttpWebRequest)WebRequest.Create("http://myexternalip.com");
                req.UserAgent = "curl"; // this simulates curl linux command
                req.Method = "GET";
                using (var response = req.GetResponse())
                {
                    using (var reader = new StreamReader(response.GetResponseStream()))
                    {
                        _extAddr = reader.ReadToEnd();
                        const string searchStartPatt = "<span id=\"ip\">";
                        const string searchEndPatt = "</span>";
                        var i = _extAddr.IndexOf(searchStartPatt, StringComparison.Ordinal);
                        if (i >= 0)
                        {
                            _extAddr = _extAddr.Substring(i + searchStartPatt.Length);
                            _extAddr = _extAddr.Substring(0, _extAddr.IndexOf(searchEndPatt, StringComparison.Ordinal));
                        }
                        else
                            _extAddr = "Unknown...";
                    }
                }
                Debug.WriteLine("ExtIpRoutine::complete");
                if (_extHandler != null)
                    Application.Current.Dispatcher.BeginInvoke(new Action(ProcessExtIpEvent));
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                _extAddr = "Unknown...";
            }
        }

        /// <summary>
        /// For dispatcher
        /// </summary>
        private void ProcessExtIpEvent()
        {
            _extHandler(this, null);
        }

        /// <summary>
        /// Callback func for ping completion event
        /// </summary>
        private void PingDoneCallback(object sender, PingCompletedEventArgs e)
        {
            if (e.Cancelled || (e.Error != null))
            {
                _inetAlive = false;
                return;
            }
            if (e.Reply.Status == IPStatus.Success)
                _inetAlive = true;
        }
        #endregion Private helpers
    }
}